package com.draw.cli.gui.panel.play;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.concurrent.Semaphore;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JPanel;

import com.draw.cli.gui.panel.Refreshable;
import com.draw.core.Drawing;
import com.draw.core.Line;
import com.draw.core.Point;
import com.draw.core.Vector;

public class PlayPanel extends JPanel implements Runnable, ActionListener, Refreshable {
	private static final long serialVersionUID = 2551109535538562321L;

	private static final Dimension size = new Dimension(400, 500);
	private static final int DELTA_LINE = 10;
	private static final int DELTA_POINT = 1;

	private static PlayPanel instance = new PlayPanel();

	public static PlayPanel getInstance() {
		return instance;
	}

	private JPanel main;
	private JButton button;
	private WordMakerPanel wordMaker;

	private Semaphore sem;
	private Drawing drawing;

	private BufferedImage buffer;

	public PlayPanel() {
		this.setLayout(new BorderLayout());
		this.drawing = null;
		this.sem = new Semaphore(1);
		this.wordMaker = new WordMakerPanel();
		JPanel pan = new JPanel(new FlowLayout());
		this.main = new JPanel(){
			private static final long serialVersionUID = -9183137590850396898L;

			public void paint (Graphics g) {
				super.paint(g);
				this.setBackground(java.awt.Color.WHITE);
				if (buffer != null) {
					g.drawImage(buffer, 0, 0, this);
				}
			}
		};
		this.main.setBorder(BorderFactory.createLoweredBevelBorder());
		this.main.setPreferredSize(size);
		this.main.setBackground(java.awt.Color.WHITE);
		JPanel left = new JPanel(new FlowLayout());
		this.button = new JButton("Jouer");
		this.button.addActionListener(this);
		left.add(this.button);
		this.add(left, BorderLayout.WEST);
		pan.add(this.main);
		this.add(pan, BorderLayout.CENTER);
		this.add(this.wordMaker, BorderLayout.SOUTH);
	}

	public void initialize(Drawing drawing) {
		this.drawing = drawing;
		this.drawing.populate();
		this.wordMaker.initialize(drawing);
		this.buffer = new BufferedImage(size.width, size.height,
				BufferedImage.TYPE_4BYTE_ABGR);
	}

	public void play() {
		try {
			this.sem.acquire();
		} catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		this.button.setEnabled(false);
		this.main.repaint();
		for (Line line : this.drawing.getLines()) {
			this.drawLine(line);
			try {
				Thread.sleep(DELTA_LINE);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.button.setEnabled(true);
		this.sem.release();
	}

	private void drawLine(Line line) {
		for (Vector vector : line.getVectors()) {
			this.drawVector(line, vector);
		}
	}

	private void drawVector(Line line, Vector vector) {
		int x_s = vector.getSource().getX();
		int y_s = vector.getSource().getY();
		int x_d = vector.getDestination().getX();
		int y_d = vector.getDestination().getY();
		Point p = new Point();
		if (x_s == x_d) {
			for (int i = y_s; i <= y_d; i++) {
				p.setX(x_s);
				p.setY(i);
				this.drawPoint(line, vector, p);
			}
			for (int i = y_d; i <= y_s; i++) {
				p.setX(x_s);
				p.setY(i);
				this.drawPoint(line, vector, p);
			}
		} else if (y_s == y_d) {
			for (int i = x_s; i <= x_d; i++) {
				p.setX(i);
				p.setY(y_s);
				this.drawPoint(line, vector, p);
			}
			for (int i = x_d; i <= x_s; i++) {
				p.setX(i);
				p.setY(y_s);
				this.drawPoint(line, vector, p);
			}
		} else {
			double a = ((double) (y_d - y_s)) / ((double) (x_d - x_s));
			double b = y_s - a * x_s;
			for (int i = x_s; i <= x_d; i++) {
				p.setX(i);
				p.setY((int) (a * i + b));
				this.drawPoint(line, vector, p);
			}
			for (int i = x_d; i <= x_s; i++) {
				p.setX(i);
				p.setY((int) (a * i + b));
				this.drawPoint(line, vector, p);
			}
			for (int i = y_s; i <= y_d; i++) {
				p.setX((int) ((i - b) / a));
				p.setY(i);
				this.drawPoint(line, vector, p);
			}
			for (int i = y_d; i <= y_s; i++) {
				p.setX((int) ((i - b) / a));
				p.setY(i);
				this.drawPoint(line, vector, p);
			}
		}
	}

	private void drawPoint(Line line, Vector vector, Point point) {
		int x = point.getX();
		int y = point.getY();
		if (x >= 0 && y >= 0 && x < size.width && y < size.height) {
			Graphics g1 = this.buffer.getGraphics();
			Graphics g2 = this.main.getGraphics();
			g1.setColor(line.getColor().getColor());
			g2.setColor(line.getColor().getColor());
			g1.fillOval(x, y, line.getThickness(), line.getThickness());
			g2.fillOval(x, y, line.getThickness(), line.getThickness());
			g1.dispose();
			g2.dispose();
		}
		try {
			Thread.sleep(DELTA_POINT);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void run() {
		this.play();
	}

	@Override
	public void actionPerformed(ActionEvent arg0) {
		Thread th = new Thread(this);
		th.start();
	}

	@Override
	public void refresh() {
		// TODO Auto-generated method stub
		
	}
}
